﻿using System;
using System.Threading;
using PoolKit.Commands;

namespace PoolKit.Tests
{
    internal class CountingCommandProcessorFake : ICommandProcessor
    {
        private readonly ICommandProcessor _commandProcessorToWrap;
        private int _numberOfTimesDelayedCommandRan;
        private readonly object _criticalSection = new object();

        public CountingCommandProcessorFake(ICommandProcessor commandProcessorToWrap)
        {
            if (commandProcessorToWrap == null) throw new ArgumentNullException("commandProcessorToWrap");

            _commandProcessorToWrap = commandProcessorToWrap;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            _commandProcessorToWrap.Dispose();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="commandToEnqueue"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ObjectDisposedException"></exception>
        public void EnqueueCommand(Command commandToEnqueue)
        {
            _commandProcessorToWrap.EnqueueCommand(commandToEnqueue);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="handleToWaitOn"></param>
        /// <param name="commandToRunWhenHandleSignals"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ObjectDisposedException"></exception>
        public void RegisterCommandWaitingForHandleSignal(WaitHandle handleToWaitOn, Command commandToRunWhenHandleSignals)
        {
            _commandProcessorToWrap.RegisterCommandWaitingForHandleSignal(handleToWaitOn, commandToRunWhenHandleSignals);
        }

        public void RegisterDelayedCommand(Command commandToRun, TimeSpan amountOfTimeToWaitBeforeRunningCommand)
        {
            Command commandWrapped = new
                ActionCommand(delegate()
                                  {
                                      commandToRun.Execute();

                                      lock (_criticalSection)
                                      {
                                          _numberOfTimesDelayedCommandRan++;
                                      }
                                  });

            _commandProcessorToWrap.RegisterDelayedCommand(commandWrapped, amountOfTimeToWaitBeforeRunningCommand);
        }

        public int NumberOfTimesDelayedCommandRan
        {
            get
            {
                lock (_criticalSection)
                {
                    return _numberOfTimesDelayedCommandRan;
                }
            }
        }
    }
}